package gomz.server;


import gomz.res.Category;
import gomz.res.Hexagram;
import gomz.res.HexagramCore;
import gomz.res.Question;
import gomz.res.QuestionCore;
import gomz.res.User;
import gomz.res.UserCore;

import java.util.ArrayList;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.Timestamp;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;


/**
 * Diese Klasse enthaelt alle DB Queries sowie die Verbindung zur Datenbank
 * @author Neuenschwander
 * 
 */ 


public class DBConnection {
// ********************************************************************************
// Variablen
// ********************************************************************************
	
	private static final String DB_DRIVER = "com.mysql.jdbc.Driver";
	private static final String DB_CONNECTION = "jdbc:mysql://localhost/gomz";
	
	private User activeUser;
	private Connection con;
	private PreparedStatement s;
	
// ********************************************************************************
// Getter/Setter
// ********************************************************************************
    
	public User getActiveUser() {
		return activeUser;
	}

	public void setActiveUser(User activeUser) {
		this.activeUser = activeUser;
	}

// ********************************************************************************
// Konstruktor
// ********************************************************************************
    /**
     * Konstruktor fuer DBConnection
     * @param dbUser Username fuer die Verbindung zur Datenbank
     * @param dbPassword Password fuer die Verbindung zur Datenbank
    */
	public DBConnection(String dbUser, String dbPassword) {
		con = getDBConnection(dbUser, dbPassword);
	}
	
// ********************************************************************************
// Methoden
// ********************************************************************************

	// ********************************************************************************
	// DB Connection - get, close
	// ********************************************************************************
    /**
     * Diese Methode stellt die Verbindung zur Datenbank mit DB Usernamen und Passwort her.
     * @param dbUser Username fuer die Verbindung zur Datenbank
     * @param dbPassword Password fuer die Verbindung zur Datenbank
     * @return Connection Liefert Verbindung zur Datenbank.
     */
	private Connection getDBConnection(String dbUser, String dbPassword) {
		 
		Connection dbConnection = null;
		try {
			Class.forName(DB_DRIVER);
		} catch (ClassNotFoundException e) {
			System.out.println("DB Conection Error");
		}
		try {
			//Datenbank Verbindung herstellen
			dbConnection = DriverManager.getConnection(DB_CONNECTION, dbUser,dbPassword);
			return dbConnection;
		} catch (SQLException e) {
			return null;
		}
	}
    /**
     * Diese Methode beendet das PreparedStatement und die Datenbankverbindung.
     */
	public void closeCon(){
		try {
			//Prepared Statement schliessen
			if(s != null){
				s.close();
			}
			//Datenbank Verbindung schliessen
			if(con != null){
			con.close();
			}
		} catch (SQLException e) {
			
		}
	}
	
	// ********************************************************************************
	// Query Execution - DbQuery, DbUpdate
	// ********************************************************************************
    /**
     * Diese Methode fuehrt ein Select Query aus und liefert das entstandene ResultSet.
     * @param preparedStatement Query das ausgefuehrt werden soll.
     * @return ResultSet Gibt Resultset mit allen Eintraegen gemaess Select Query aus.
     */
	public synchronized ResultSet DbQuery(PreparedStatement preparedStatement){
		ResultSet rs = null;
		try{
			//Select Query durchfuehren und in ResultSet speichern
			return rs = preparedStatement.executeQuery ();
		}
		catch (Exception e){
			return rs;
		}
	}
    /**
     * Diese Methode fuehrt ein Query aus und gibt true zurueck falls erfolgreich.
     * @param preparedStatement Query das ausgefuehrt werden soll.
     * @return Boolean True wenn Query erfolgreich durchgefuehrt werden konnte, sonst false.
     */
	public synchronized Boolean DbUpdate(PreparedStatement preparedStatement){
		try{
			//Query durchfuehren, wenn Rueckgabe groesser als 1, true zurueckgeben
			int i =preparedStatement.executeUpdate();
			if(i >= 1 ){
				return true;
			}
		}
		catch (Exception e){
			return false;
		}
		return false;
	}
    /**
     * Diese Methode fuehrt ein Query aus und liefert den generierten Wert zurueck.
     * @param preparedStatement Query das ausgefuehrt werden soll.
     * @return Integer Autogenerierte ID des neuen Datenbankeintrags.
     */
	public synchronized Integer DbUpdateReturnId(PreparedStatement preparedStatement){
		try{
			//Query ausfuehren
			preparedStatement.executeUpdate();
			//ResultSet aus allen generierten Keys herstellen
			ResultSet rs = preparedStatement.getGeneratedKeys();
			while (rs.next()){
			//Erste generierte ID zurueckgeben
			return (rs.getInt(1));
			}
		}catch (Exception e){
				return 0;
			}
		return 0;
	}
	
	// ********************************************************************************
	// UserCore - get, userLogin, getAll
	// ********************************************************************************
    /**
     * Diese Methode speichert die UserID in den uebergebenen Benutzer
     * @param user Benutzer fuer den Benutzernamen.
     * @return Boolean true wenn Eintrag fuer Benutzernamen vorhanden, sonst false.
     */
	public boolean getUserId(UserCore user){
		try {
			//PreparedStatement erstellen
			s = con.prepareStatement("select UserID from t_User where Username = ?");
			//Usernamen setzen
			s.setString(1, user.getUsername());
			//Query Resultat in ResultSet speichern
			ResultSet rs = DbQuery(s);
			while (rs.next()){
				//UserID setzen
				user.setId(rs.getInt(1));
				return true;
			}
		} catch (SQLException e1) {
			return false;
		}
		return false;
	}
    /**
     * Diese Methode ueberprueft ob Username und Passwort eines Benutzers stimmen und gibt true oder false zurueck.
     * @param user Benutzer der versucht einzuloggen.
     * @return Boolean True wenn Login funktionieren soll, sonst false.
     */
	public boolean userLogin(UserCore user){
		try {
			//PreparedStatement erstellen
			s = con.prepareStatement("select UserID from t_User where Username = ? and Userpassword = ?");
			//Username auf ersten Platzhalter setzen
			s.setString(1, user.getUsername());
			//Userpasswort auf zweiten Platzhalter setzen
			s.setString(2, user.getPassword());
			//Resultat in ResultSet speichern
			ResultSet rs = DbQuery(s);
			//Wenn kein Eintrag vorhanden false zurueckgeben
			if (!rs.next()) {
			    return false;
			//Sonst das erste Resultat als UserID setzen und true zurueckgeben
			} else {
				rs.last();
				if (rs.getRow() == 1){
				user.setId(rs.getInt(1));
				return true;
				}		
			}
		} 	catch (SQLException e) {
				return false;
			}
		return false;
	}
    /**
     * Diese Methode liefert eine ArrayList mit allen Benutzern (ID, Name und Passwort) zurueck.
     * @return ArrayList<UserCore> ArrayList mit allen Benutzern.
     */
	public ArrayList<UserCore> userGetAll(){
		
		ArrayList<UserCore> al = null;
		try {
		//PreparedStatement erstellen
		s = con.prepareStatement("Select UserID, Username, Userpassword from t_User");
		//Resultat in ResultSet speichern
		ResultSet rs = DbQuery(s);
			while (rs.next()){
				//Beim ersten Eintrag ArrayList mit UserCores erstellen
				if(rs.isFirst()){
					al = new ArrayList<UserCore>();
				}
				//User erstellen und Daten setzen (ID, Username und Passwort)
				User user = new User();
				user.setId(rs.getInt(1));
				user.setUsername(rs.getString(2));
				user.setPassword(rs.getString(3));
				//User in ArrayList hinzufuegen
				al.add(user);
			}
		} catch (SQLException e) {
			return null;
		}
		//ArrayList zurueckgeben
		return al ;
	}
	
	// ********************************************************************************
	// User - Save, Get, Delete
	// ********************************************************************************
    /**
     * Diese Methode speichert einen neuen Benutzer oder aendert einen Bestehenden.
     * @param user Benutzer der gespeichert werden soll.
     * @return User Benutzer der erstellt wurde, wird zurueckgegeben.
     */
	public User userSave(User user){
		
		ResultSet rs = null;
		//Wenn User neu ist
		if (user.getId() == 0){
			try {
				//PreparedStatement erstellen, besteht der aktuelle User bereits?
				s = con.prepareStatement("select UserID from t_User where Username =?");
				//Username an ersten Platzhalter einfuegen
				s.setString(1, user.getUsername());
				//Resultat in ResultSet speichern
				rs = DbQuery(s);
				//Wenn Eintrag vorhanden nichts zurueckgeben.
				if (rs.next()) {
				    return null;
				}
				//PreparedStatement erstellen, neuen User in Tabelle t_User einfuegen
				s = con.prepareStatement("insert into t_User (Firstname, Lastname, Mail, Admin, Username, Userpassword, Language) VALUES (?, ?, ?, ?, ?, ?, ?) ", Statement.RETURN_GENERATED_KEYS);
				//Vorname an ersten Platzhalter setzen
				s.setString(1, user.getVorname());
				//Nachname an zweiten Platzhalter setzen
				s.setString(2, user.getNachname());
				//Mailadresse an dritten Platzhalter setzen
				s.setString(3, user.geteMail());
				//Wenn User Admin ist, 1 an vierten Platzhalter setzen, sonst 0
				s.setInt(4, (user.isAdmin() == true?1:0));
				//Username an fuenften Platzhalter setzen
				s.setString(5, user.getUsername());
				//Passwort an sechsten Platzhalter setzen
				s.setString(6, user.getPassword());
				//Sprachen ID an siebten Platzhalter setzen. 1 fuer Deutsch, 2 fuer English
				s.setInt(7, user.getLanguage());
				//Wenn Query nicht erfolgreich war null zurueckgeben
				user.setId(DbUpdateReturnId(s));
			} catch (SQLException e) {
				return null;
			}
			//Wenn User schon existiert
		} else {
			try {
				//PreparedStatement erstellen, geaenderte Userdaten speichern
				s = con.prepareStatement("update t_User set Firstname = ?, Lastname = ?, Mail = ?, Admin = ?, Username = ?, Userpassword = ?, Language = ? where UserID = ?");
				//Vorname an ersten Platzhalter setzen
				s.setString(1, user.getVorname());
				//Nachname an zweiten Platzhalter setzen
				s.setString(2, user.getNachname());
				//Mail an dritten Platzhalter setzen
				s.setString(3, user.geteMail());
				//Wenn User Admin ist, Platzhalter an vierter Stelle auf eins setzen, sonst auf null.
				s.setInt(4, (user.isAdmin() == true?1:0));
				//Username an fuenften Platzhalter setzen
				s.setString(5, user.getUsername());
				//Passwort an sechsten Platzhalter setzen
				s.setString(6, user.getPassword());
				//Sprachen an siebten Platzhalter setzen
				s.setInt(7, user.getLanguage());
				//Userid an achten Platzhalter setzen
				s.setInt(8, user.getId());
				//Wenn der aktive User derselbe wie der zu speichernde User, wird Sprache des aktiven Users angepasst.
				if (activeUser.getId() == user.getId()){
					activeUser.setLanguage(user.getLanguage());
				}
				//Query ausfuehren
				if (DbUpdate(s) == false){
					return null;
				}
			} catch (SQLException e) {
				return null;
			}
		}
		//Benutzer zurueckgeben
		return user;
	}
	
    /**
     * Diese Methode liefert einen Benutzer zurueck.
     * @param id Id des Users der zurueckgegeben werden soll.
     * @return User Benutzer der zurueckgegeben wird.
     */
	public User userGet(int id){
		User user = null;
		try {
			//PreparedStatement erstellen, alle Daten von einem User erfragen
			s = con.prepareStatement("Select * from t_User where UserID = ?");
			//Userid an ersten Platzhalter setzen
			s.setInt(1, id);
			//Resultat in ResultSet speichern
			ResultSet rs = DbQuery(s);
			while (rs.next()){
				//Wenn Resultate vorhanden User erstellen
				if(rs.isFirst()){
					user = new User();
				}
				//ID dem User hinzufuegen
				user.setId(rs.getInt(1));
				//Vorname dem User hinzufuegen
				user.setVorname(rs.getString(2));
				//Nachname dem User hinzufuegen
				user.setNachname(rs.getString(3));
				//Mail dem User hinzufuegen
				user.seteMail(rs.getString(4));
				//Admin dem User hinzufuegen
				user.setAdmin(rs.getBoolean(5));
				//Username dem User hinzufuegen
				user.setUsername(rs.getString(6));
				//Sprache dem User hinzufuegen
				user.setLanguage(rs.getInt(8));
			}
		} catch (SQLException e) {
			return null;
		}
		//User zurueckgeben
		return user;
	}
    /**
     * Diese Methode loescht einen Benutzer
     * @param id Id des zu loeschenden Benutzers.
     * @return boolean True wenn das Loeschen erfolgreich war, sonst false.
     */
	public boolean userDelete (int id){
		
		try {
			//PreparedStatement erstellen, User mit gegebener UserID loeschen
			s = con.prepareStatement("DELETE FROM t_User WHERE UserID = ?");
			//UserID an Platzhalter eins setzen
			s.setInt(1, id);
		} catch (SQLException e) {
			return false;
		}
		//Query ausfuehren, wenn erfolgreich true, sonst false
		return DbUpdate(s);
	}
	
	// ********************************************************************************
	// Question - Save, Edit, Delete, Get
	// ********************************************************************************
    /**
     * Diese Methode speichert eine Fragestellung, oder aendert eine Bestehende.
     * @param question Fragestellung die gespeichert werden soll.
     * @return int Gibt Id der gespeicherten Fragestellung zurueck.
     */
	public int questionSave(Question question){

		int problemId = 0;
		//HexagramID aus Lines Array holen
		Integer hexagramId = question.transformId(question.getLines());
		//Lines Array in String umwandeln
		String lines="";
		for (int i=0;i<question.getLines().length;i++)
		{
			lines += question.getLines()[i];
		}
		//Wenn Fragestellung neu ist
		if (question.getId() == 0){
			try {
				//PreparedStatement erstellen, neue Fragestellung in Datenbank einfuegen
				s = con.prepareStatement("Insert into t_problem (t_HexagramID, t_UserID, Title, Question, Analysis, Synthesis, Feedback, Created, Edited, Public, HexLines) select hexagramID as t_HexagramID, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? from t_hexagram where internalid =? and Language = ?", Statement.RETURN_GENERATED_KEYS);
				//UserID an ersten Platzhalter setzen
				s.setInt(1, activeUser.getId());
				//Titel der Frage an zweiten Platzhalter setzen
				s.setString(2, question.getTitle());
				//Frage an dritten Platzhalter setzen
				s.setString(3, question.getQuestion());
				//Analyse an vierten Platzhalter setzen
				s.setString(4, question.getAnalysis());
				//Synthese an fuenften Platzhalter setzen
				s.setString(5, question.getSynthesis());
				//Feedback an sechsten Platzhalter setzen
				s.setString(6, question.getFeedback());
				//Erstellungsdatum an siebten Platzhalter setzen
				s.setTimestamp(7,UtilDateToSqlDate((question.getCreated())));
				//Bearbeitungsdatum an siebten Platzhalter setzen
				s.setTimestamp(8,UtilDateToSqlDate((question.getEdited())));
				//Wenn isPublic true eine 1 auf Platzhalter 9 setzen, sonst 0
				s.setInt(9, (question.isIsPublic() == true?1:0));
				//Lines an Platzhalter 10 setzen
				s.setString(10, lines);
				//HexagramID an Platzhalter 11 setzen
				s.setInt(11, hexagramId);
				//Sprache an Platzhalter 12 setzen
				s.setInt(12, activeUser.getLanguage());
				//Query ausfuehren und generierte ProblemID speichern
				problemId = DbUpdateReturnId(s);
				//Durch alle Kategorien einer eingegebenen Frage
				for (int i = 0;i<question.getCat().size();i++){
					//PreparedStatement erstellen, Frage - Kategorieverknuepfung erstellen
					s = con.prepareStatement("insert into t_problem_to_category (t_problemID, t_categoryID) values (?, ?)");
					//ProblemID an ersten Platzhalter setzen
					s.setInt(1, problemId);
					//CategoryID holen und an zweiten Platzhalter setzen
					s.setInt(2, question.getCat().get(i).getId());
					//Wenn Query nicht erfolgreich war
					if (DbUpdate(s) == false){
						//ProblemID auf null setzen
						problemId = 0;
					}
				}
			} catch (SQLException e) {
				return 0;
			}
			
		} else {
			try {
				problemId = question.getId();
				//PreparedStatement erstellen, bestehende Fragestellung mit neuen Daten speichern
				s = con.prepareStatement("Update t_problem set t_HexagramID = (select HexagramID from t_hexagram where InternalID = ? and Language = ?), Title = ?, Question = ?, Analysis = ?, Synthesis = ?, Feedback = ?, Created = ?, Edited = ?, Public = ?, HexLines = ? where ProblemID = ?");
				//HexagrammID an ersten Platzhalter setzen
				s.setInt(1, hexagramId);
				//Sprache an zweiten Platzhalter setzen
				s.setInt(2, activeUser.getLanguage());
				//Titel der Fragestellung an dritten Platzhalter setzen
				s.setString(3, question.getTitle());
				//Fragestellung an vierten Platzhalter setzen
				s.setString(4, question.getQuestion());
				//Analyse an fuenften Platzhalter setzen
				s.setString(5, question.getAnalysis());
				//Synthese an sechsten Platzhalter setzen
				s.setString(6, question.getSynthesis());
				//Feedback an siebten Platzhalter setzen
				s.setString(7, question.getFeedback());
				//Erstellungsdatum an achten Platzhalter setzen
				s.setTimestamp(8,UtilDateToSqlDate((question.getCreated())));
				//Bearbeitungsdatum an neunten Platzhalter setzen
				s.setTimestamp(9,UtilDateToSqlDate((question.getEdited())));
				//Wenn isPublic true eine 1 auf Platzhalter zehn setzen, sonst 0
				s.setInt(10, (question.isIsPublic() == true?1:0));
				//Lines an elften Platzhalter setzen
				s.setString(11, lines);
				//FragestellungsID an zwoelften Platzhalter setzen
				s.setInt(12, question.getId());
				//Query ausfuehren
				DbUpdate(s);
				//PreparedStatement erstellen, alle vorhandenen Kategorien einer Frage loeschen
				s = con.prepareStatement("delete from t_problem_to_category where t_problemID = ?");
				//FragestellungsID an ersten Platzhalter setzen
				s.setInt(1, question.getId());
				//Query ausfuehren
				DbUpdate(s);
				//Fuer jede Kategorie einer Fragestellung
				for (int i = 0;i<question.getCat().size();i++){
					//PreparedStatement erstellen, Kategorie der Fragestellung in der Datenbank zuordnen
					s = con.prepareStatement("insert into t_problem_to_category (t_problemID, t_categoryID) values (?, ?)");
					//FragestellungsID an ersten Platzhalter setzen
					s.setInt(1, question.getId());
					//Kategorie der Fragestellung an Platzhalter zwei setzen
					s.setInt(2, question.getCat().get(i).getId());
					//Wenn Query erfolgreich, FragestellungsID zurueckgeben 
					if (DbUpdate(s) == false){
						problemId = 0;
					}
				}
			} catch (SQLException e) {
				return 0;
			}		
		}
		//FragestellungsID zurueckgeben
		return problemId;
	}
    /**
     * Diese Methode loescht eine Fragestellung und dessen Verlinkungen mit Kategorien.
     * @param id Id der zu loeschenden Fragestellung.
     * @return boolean Liefert true zurueck wenn das Loeschen funktioniert hat, sonst false.
     */
	public boolean questionDelete(int id){
		
		try {
			//PreparedStatement erstellen, alle Kategorien einer Fragestellung loeschen
			s = con.prepareStatement("DELETE FROM t_problem_to_category WHERE t_ProblemID = ?");
			//FragestellungsID an ersten Platzhalter setzen
			s.setInt(1, id);
			//Query ausfuehren
			DbUpdate(s);
			//PreparedStatement erstellen, Fragestellung mit gegebener ID loeschen
			s = con.prepareStatement("DELETE FROM t_Problem WHERE ProblemID = ?");
			//FragestellungsID an ersten Platzhalter setzen
			s.setInt(1, id);
		} catch (SQLException e) {
			return false;
		}
		//True oder False ausgeben, je nach Erfolg der Queryausfuehrung
		return DbUpdate(s);
	}
    /**
     * Diese Methode liefert eine Fragestellung zurueck die mit der Id angefordert wurde.
     * @param id Id der zurueckzugebenden Fragestellung.
     * @return Question Fragestellung mit allen Daten aus der Datenbank.
     */
	public Question questionGet(int id){
		Question question = null;
		try {
			//PreparedStatement erstellen, Fragestellung und dessen original Hexagrammtexte werden ausgelesen
			s = con.prepareStatement("Select * from t_Problem as prob join (t_Hexagram as hex) ON (prob.t_HexagramID = hex.HexagramID)  where prob.ProblemID = ?");
			//FragestellungsID wird an ersten Platzhalter gestellt
			s.setInt(1, id);
			//Query ausfuehren und in ResultSet speichern
			ResultSet rs = DbQuery(s);
			while (rs.next()){
				//Beim ersten Resultat
				if(rs.isFirst()){
					//Neue Fragestellung erstellen
					question = new Question();
				}
				//ID setzen
				question.setId(rs.getInt(1));
				//Titel setzen
				question.setTitle(rs.getString(4));
				//Fragestellung setzen
				question.setQuestion(rs.getString(5));
				//Analyse setzen
				question.setAnalysis(rs.getString(6));
				//Synthese setzen
				question.setSynthesis(rs.getString(7));
				//Feedback setzen
				question.setFeedback(rs.getString(8));
				//Erstellungsdatum setzen
				question.setCreated(rs.getDate(9));
				//Bearbeitungsdatum setzen
				question.setEdited(rs.getDate(10));
				//Public auf true setzen wenn Eintrag 1 sonst false
				question.setIsPublic(rs.getBoolean(11));
				//Kategorien der Fragestellung setzen
				question.setCat(catGet(rs.getInt(1)));
				//User der Fragestellung setzen
				question.setUser(userGet(rs.getInt(3)));
				//Lines Array mit Daten fuellen
				int[] lines = new int[6];
				for (int i=0;i <6;i++){
					String cc = rs.getString(12);
					char[] c = cc.toCharArray();
					lines[i] = Integer.parseInt("" + c[i]);
				}
				//Lines setzen
				question.setLines(lines);
				//Array fuer Hexagramme erstellen
				Hexagram[] hex = new Hexagram[12];
				//PreparedStatement erstellen, Referenzhexagramme des Fragestellungs Hexagramms suchen
				s = con.prepareStatement("select hexagramid,nuclear,inverse,reverse,fuxi from t_hexref join (select hexagramID,internalID from t_hexagram where hexagramID=?) as j  on (t_hexref.hexrefID=j.InternalID)");
				//FragestellungsID an ersten Platzhalter setzen
				s.setInt(1, rs.getInt(2));
				//Query ausfuehren und in ResultSet speichern
				ResultSet rs2 = DbQuery(s);
				try {
					//Hexagramme einer Fragestellung speichern, true wenn interne IDs verwendet werden, false wenn mit den Original IDs gearbeitet wurde
					while (rs2.next()){
						//Kontexthexagramm speichern 
						hex[0] = hexagramGet(rs2.getInt(1), false);
						//Perspektivhexagramm speichern
						hex[1] = hexagramGet(question.getPerspektivHexagramId(lines), true);
						//Komplementaerhexagramm speichern
						hex[2] = hexagramGet(rs2.getInt(3), false);
						//Wendehexagramm speichern
						hex[3] = hexagramGet(rs2.getInt(4), false);
						//Nuklearhexagramm speichern
						hex[4] = hexagramGet(rs2.getInt(2), false);
						//Fuxihexagramm speichern
						hex[5] = hexagramGet(rs2.getInt(5), false);
						//For Schleife fuer die sechs Linienhexagramme
						for (int i = 0; i < 6;i++){
							//Linienhexagramme speichern
							hex[i+6] = hexagramGet(question.getLineHexagramId(lines)[i], true);
						}
					}
				} catch (SQLException e) {
					e.printStackTrace();
				}
				//Hexagramme setzen
				question.setHex(hex);
			}
		} catch (SQLException e) {
			return null;
		}
		//Fragestellung zurueckgeben
		return question;
	}
	
	// ********************************************************************************
	// QuestionCore - getAll
	// ********************************************************************************
    /**
     * Diese Methode liefert alle Fragestellungen eines Benutzers und die oeffentlichen Fragestellungen sortiert nach Bearbeitungsdatum zurueck.
     * @return ArrayList<QuestionCore> ArrayList mit allen Fragen des aktiven Users.
     */
	public ArrayList<QuestionCore> questionGettAll(){
		ArrayList<QuestionCore> al = null;

		try {
			//PreparedStatement erstellen, alle Fragestellungen eines Users und die oeffentlichen Fragestellungen
			s = con.prepareStatement("select * from t_problem where t_UserID = ? or Public = ? ORDER BY Edited desc");
			//UserID an ersten Platzhalter setzen
			s.setInt(1, activeUser.getId());
			//Public an zweiten Platzhalter setzen
			s.setInt(2, 1);
			//Query ausfuehren und in ResultSet speichern
			ResultSet rs = DbQuery(s);
			while (rs.next()){
				if(rs.isFirst()){
					//ArrayList mit QuestionCores erstellen
					al = new ArrayList<QuestionCore>();
				}
				//Neue Fragestellung 
				Question question = new Question();
				//ID setzen
				question.setId(rs.getInt(1));
				//Titel setzen
				question.setTitle(rs.getString(4));
				//Fragestellung setzen
				question.setQuestion(rs.getString(5));
				//Bearbeitungsdatum setzen
				question.setEdited(rs.getDate(10));
				//Public setzen
				question.setIsPublic(rs.getBoolean(11));
				//User setzen
				question.setUser(userGet(rs.getInt(3)));
				//Kategorien setzen
				question.setCat(catGet(rs.getInt(1)));
				//Fragestellung der Arraylist hinzufuegen
				al.add(question);
			}
		} catch (SQLException e) {
			return null;
		}
		//ArrayList zurueckgeben
		return al;
	}

	// ********************************************************************************
	// Category - Save, Delete, Get
	// ********************************************************************************
    /**
     * Diese Methode loescht die Kategorie mit der uebergebenen Id.
     * @param id Id einer Kategorie die geloescht werden soll.
     * @return boolean Wenn die Kategorie geloescht werden konnte True, sonst False.
     */
	public boolean catDelete(int id){

		try {
			//PreparedStatement erstellen, alle Fragestellungen einer Kategorie loeschen
			s = con.prepareStatement("DELETE FROM t_problem_to_category WHERE t_CategoryID = ?");
			//KategorieID an ersten Platzhalter setzen
			s.setInt(1, id);
			//Query ausfuehren
			DbUpdate(s);
			//PreparedStatement erstellen, Kategorie mit gegebener ID loeschen
			s = con.prepareStatement("DELETE FROM t_Category WHERE CategoryID = ?");
			//KategorieID an ersten Platzhalter setzen
			s.setInt(1, id);
		} catch (SQLException e) {
			return false;
		}
		//Query ausfuehren und true oder false zurueckgeben
		return DbUpdate(s);
	}
    /**
     * Diese Methode speichert eine Kategorie, oder aendert eine Bestehende.
     * @param cat Zu speichernde Kategorie.
     * @return Category Gibt die Kategorie zurueck, nachdem sie gespeichert wurde.
     */
	public Category catSave(Category cat){
		//Wenn Kategorie neu erstellt werden soll
		if (cat.getId() == 0){
			try {
				//PreparedStatement erstellen, neue Kategorie in Datenbank speichern, generierte ID zurueckgeben
				s = con.prepareStatement("insert into `t_Category` (Name,t_UserID) Values (?, ?)", Statement.RETURN_GENERATED_KEYS);
				//Name der Kategorie an ersten Platzhalter setzen
				s.setString(1, cat.getName());
				//UserID an zweiten Platzhalter setzen
				s.setInt(2, activeUser.getId());
			} catch (SQLException e) {
				return null;
			}
			//ID der neuen Kategorie setzen
			cat.setId(DbUpdateReturnId(s));
			//Kategorie zurueckgeben
			return cat;
		} else {
			try {
				//PreparedStatement erstellen,  Kategorienamen aendern
				s = con.prepareStatement("update t_Category set Name = ?,t_UserID = ? where CategoryID = ?");
				//Kategorienamen an ersten Platzhalter setzen
				s.setString(1, cat.getName());
				//UserID an zweiten Platzhalter setzen
				s.setInt(2, activeUser.getId());
				//KategorieID an dritten Platzhalter setzen
				s.setInt(3, cat.getId());
			} catch (SQLException e) {
				return null;
			}
			//Query ausfuehren
			DbUpdate(s);
			//Kategorie zurueckgeben
			return cat;
		}
	}
    /**
     * Diese Methode gibt alle Kategorien des aktiven Users zurueck.
     * @return ArrayList<Category> ArrayList mit allen Kategorien (ID und Name) eines Benutzers.
     */
	public ArrayList<Category> catGetAll(){
	 	ArrayList<Category> cat =null;
		try {
			//PreparedStatement erstellen, alle Kategorien eines Users anzeigen
			s = con.prepareStatement("Select * from t_Category where t_UserID = ?");
			//UserID an ersten Platzhalter setzen
			s.setInt(1, activeUser.getId());
			//Query ausfuehren und in ResultSet speichern
			ResultSet rs = DbQuery(s);
			while (rs.next()){
					if (rs.isFirst()){
						//Neue Kategorie ArrayList
						cat = new ArrayList<Category>();
					}
					//Neue Kategorie
					Category category = new Category();
					//ID setzen
					category.setId(rs.getInt(1));
					//Name setzen
					category.setName(rs.getString(3));
					//Kategorie der ArrayList hinzufuegen
					cat.add(category);
			}
		} catch (SQLException e) {
			return null;
		}
		//Kategorie zurueckgeben
		return cat;	
	}
	
    /**
     * Diese Methode gibt alle Kategorien fuer eine Fragestellung des aktiven Benutzers zurueck.
     * @param problemId ID der Fragestellung
     * @return ArrayList<Category> ArrayList mit allen Kategorien (ID und Name) einer Fragestellung.
     */
	public ArrayList<Category> catGet(int problemId){
	ArrayList<Category> alCat = null;
	try {
		//PreparedStatement erstellen, Kategorien fuer eine Fragestellung auslesen
		s = con.prepareStatement("select categoryID, Name from t_category cat right join t_problem_to_category catprob on catprob.t_categoryid = cat.categoryid and cat.t_userid = ? where catprob.t_problemid=?");
		//UserID an ersten Platzhalter setzen
		s.setInt(1, activeUser.getId());
		//FragestellungsID an zweiten Platzhalter setzen
		s.setInt(2, problemId);
		//Query ausfuehren und in ResultSet speichern
		ResultSet rs2 = DbQuery(s);
		while (rs2.next()){
			if(rs2.isFirst()){
				//Neue Kategorie ArrayList
				alCat = new ArrayList<Category>();
			}
			//Neue Kategorie
			Category category = new Category();
			//ID setzen
			category.setId(rs2.getInt(1));
			//Namen setzen
			category.setName(rs2.getString(2));
			//Kategorie der ArrayList hinzufuegen
			alCat.add(category);				
		}
	} catch (SQLException e) {
		return null;
	}
	//ArrayList zurueckgeben
	return alCat;
	}
	
	// ********************************************************************************
	// Hexagram - Save
	// ********************************************************************************
    /**
     * Diese Methode sichert Hexagramme in die Datenbank.
     * @param hex Zu sicherndes Hexagram.
     * @param saveOriText True wenn Originaltexte von Hexagrammen auch gesichert werden soll.
     * @return boolean true wenn Query erfolgreich ausgefuehrt werden konnte, ansonsten false.
     */
	public boolean hexagramSave(Hexagram hex, Boolean saveOriText){
			
		try {
			//Wenn Originaltexte auch gesichert werden sollen
			if (saveOriText){
				//PreparedStatement erstellen, original Hexagrammtexte speichern
				s = con.prepareStatement("Update t_hexagram set Commentary = ? , Judgement = ? , Image = ? , Line1 = ? , Line2 = ? , Line3 = ? , Line4 = ? , Line5 = ? , Line6 = ? where InternalID = ? and Language = ?");
				//Kommentar an ersten Platzhalter setzen
				s.setString(1, hex.getComment()[0]);
				//Urteil an zweiten Platzhalter setzen
				s.setString(2, hex.getJudgement()[0]);
				//Image an dritten Platzhalter setzen
				s.setString(3, hex.getImage()[0]);
				//Line1 an vierten Platzhalter setzen
				s.setString(4, hex.getLine1()[0]);
				//Line2 an fuenften Platzhalter setzen
				s.setString(5, hex.getLine2()[0]);
				//Line3 an sechsten Platzhalter setzen
				s.setString(6, hex.getLine3()[0]);
				//Line4 an siebten Platzhalter setzen
				s.setString(7, hex.getLine4()[0]);
				//Line5 an achten Platzhalter setzen
				s.setString(8, hex.getLine5()[0]);
				//Line6 an neunten Platzhalter setzen
				s.setString(9, hex.getLine6()[0]);
				//HexagrammID an zehnten Platzhalter setzen
				s.setInt(10, hex.getId());
				//Sprache an elften Platzhalter setzen
				s.setInt(11, activeUser.getLanguage());
				//Query ausfuehren, wenn fehlgeschlagen false zurueckgeben
				if (DbUpdate(s)==false){
					return false;
				}
			}
		} catch (SQLException e) {
			return false;
		}
		try {
			//PreparedStatement erstellen, Kommtenar einfuegen wenn noch nicht vorhanden, sonst ersetzen
			s = con.prepareStatement("replace into t_comment (t_HexagramID, t_UserID, Commentary, Judgement, Image, Line1, Line2, Line3, Line4, Line5, Line6) select hexagramID as t_HexagramID,?,?,?,?,?,?,?,?,?,? from t_hexagram where internalid =? and Language = ?");
			//UserID an ersten Platzhalter setzen
			s.setInt(1, activeUser.getId());
			//Kommentar an zweiten Platzhalter setzen
			s.setString(2, hex.getComment()[1]);
			//Urteil an dritten Platzhalter setzen
			s.setString(3,hex.getJudgement()[1]);
			//Image an vierten Platzhalter setzen
			s.setString(4,hex.getImage()[1]);
			//Line1 an fuenften Platzhalter setzen
			s.setString(5,hex.getLine1()[1]);
			//Line2 an sechsten Platzhalter setzen
			s.setString(6,hex.getLine2()[1]);
			//Line3 an siebten Platzhalter setzen
			s.setString(7,hex.getLine3()[1]);
			//Line4 an achten Platzhalter setzen
			s.setString(8,hex.getLine4()[1]);
			//Line5 an neunten Platzhalter setzen
			s.setString(9,hex.getLine5()[1]);
			//Line6 an zehnten Platzhalter setzen
			s.setString(10,hex.getLine6()[1]);
			//HexagrammID an elften Platzhalter setzen
			s.setInt(11,hex.getId());
			//Sprache an zwoelften Platzhalter setzen
			s.setInt(12, activeUser.getLanguage());
		} catch (SQLException e) {
			return false;
		}
		//Query ausfuehren und zurueckgeben ob erfolgreich oder nicht
		return DbUpdate(s);
	}
	
    /**
     * Diese Methode liefert ein komplettes Hexagram aus dessen Internal- oder HexagramID zurueck.
     * @param id ID eines Hexagrams, je nach isInternal, HexagramID oder InternalID.
     * @param isInternal True wenn mit InternalID gearbeitet wird, False wenn mit den offiziellen Nummern gearbeitet wird.
     * @return Hexagram mit allen Attributen.
     */
	public Hexagram hexagramGet(int id,boolean isInternal){
		Hexagram hexagram = null;
		String[][] matrix = null;
		ResultSet rs = null;
		try {
			//Wenn internalIDs verarbeitet werden sollen
			if (isInternal){
				//PreparedStatement erstellen, alle Kommentare und original Texte auslesen, ueber die InternalID
				s = con.prepareStatement("select * from t_hexagram left join (select * from t_comment where t_Userid=?) as j  on (t_hexagram.HexagramID=j.t_Hexagramid) where t_hexagram.InternalID =? and Language = ?");
			} else {
				//PreparedStatement erstellen, alle Kommentare und original Texte auslesen, ueber die HexagrammID
				s = con.prepareStatement("select * from t_hexagram left join (select * from t_comment where t_Userid=?) as j  on (t_hexagram.HexagramID=j.t_Hexagramid) where t_hexagram.HexagramID =? and Language = ?");
			}
			//UserID an ersten Platzhalter setzen
			s.setInt(1, activeUser.getId());
			//Hexagramm oder Internal ID an zweiten Platzhalter setzen
			s.setInt(2, id);
			//Sprachen an dritten Platzhalter setzen
			s.setInt(3, activeUser.getLanguage());
			//Query ausfuehren und in ResultSet speichern
			rs = DbQuery(s);
			while (rs.next()){
				if (rs.isFirst()){
					//Neues Hexagramm
					hexagram = new Hexagram();
					//Neuer zweidimensionaler Array
					matrix = new String[9][2]; 
				}
				//ID setzen
				hexagram.setId(rs.getInt(3));
				//Name setzen
				hexagram.setName(rs.getInt(1) + ". " + rs.getString(4));
				for (int i=0;i<9;i++){
					//Originaltexte in Array speichern
					matrix[i][0] = rs.getString(i+5);		
				}
				for (int i=0;i<9;i++){
					//Persoenliche Kommentare in Array speichern
					matrix[i][1] = rs.getString(i+16);
				}
				//Kommentar setzen
				hexagram.setComment(matrix[0]);
				//Urteil setzen
				hexagram.setJudgement(matrix[1]);
				//Image setzen
				hexagram.setImage(matrix[2]);
				//Linie1 setzen
				hexagram.setLine1(matrix[3]);
				//Linie2 setzen
				hexagram.setLine2(matrix[4]);
				//Linie3 setzen
				hexagram.setLine3(matrix[5]);
				//Linie4 setzen
				hexagram.setLine4(matrix[6]);
				//Linie5 setzen
				hexagram.setLine5(matrix[7]);
				//Linie6 setzen
				hexagram.setLine6(matrix[8]);
			}	
		} catch (SQLException e) {
			return null;
		}
		//Hexagramm zurueckgeben
		return hexagram;
	
	}
	
	// ********************************************************************************
	// HexagramCore - getAll
	// ********************************************************************************
    /**
     * Diese Methode fuellt alle HexagramCores aus der Datenbank in eine ArrayList und gibt diese zurueck.
     * @return ArrayList<HexagramCore> Alle Hexagrame mit deren IDs und Namen.
     */
	public ArrayList<HexagramCore> hexGetAll(){
	 	ArrayList<HexagramCore> hexTitle = null;
		try {
			//PreparedStatement erstellen,alle Hexagramme sortiert auslesen
			s = con.prepareStatement("select InternalID, HexagramID, Name, Language from t_Hexagram where Language = ? order by HexagramID asc");
			//UserID an ersten Platzhalter setzen
			s.setInt(1, activeUser.getLanguage());	
			//Query ausfuehren und in ResultSet speichern
			ResultSet rs = DbQuery(s);
			while (rs.next()){
				if (rs.isFirst()){
					//Neue HexagrammCore ArrayList
					hexTitle = new ArrayList<HexagramCore>();
				}
				//Neues Hexagramm
				Hexagram hex = new Hexagram();
				//ID setzen
				hex.setId(rs.getInt(1));
				//Namen setzen
				hex.setName(rs.getInt(2) + ". " + rs.getString(3));	
				//Hexagramm der ArrayList hinzufuegen
				hexTitle.add(hex);
			}
		} catch (SQLException e) {
			return null;
		}
		//Hexagramm zurueckgeben
		return hexTitle;
	}
	
    // ********************************************************************************
    // util.DATE to sql.DATE
    // ********************************************************************************
    /**
     * Diese Methode wandelt ein Util Date in Sql SQL Date um.
     * @param java.util.Date enthaelt Datum der Erstellung oder Bearbeitung einer Frage
     * @return sqlDate Timestamp mit dem sqlDate einer Erstellung oder Bearbeitung
     */
	public static Timestamp UtilDateToSqlDate(java.util.Date utilDate) {
		  Timestamp sqlDate = null;
		  //Wenn Datum vorhanden, Util.Date zu sql Date umwandeln
		  if (utilDate != null)  sqlDate = new Timestamp(utilDate.getTime());
		  //und zurueckgeben
		  return sqlDate;
	}
}

